package com.yuncheng.spcyApi.scheduleJob;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import org.apache.commons.collections.CollectionUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yuncheng.spcyApi.constant.schedule.ScheduleConstant;
import com.yuncheng.spcyApi.constant.common.SpcyCommonConstant;
import com.yuncheng.spcyApi.constant.common.SpcyConstant;
import com.yuncheng.spcyApi.entity.*;
import com.yuncheng.spcyApi.schedule.ActiveScheduleTask;
import com.yuncheng.spcyApi.service.ISpcyScheduleSettingService;
import com.yuncheng.spcyApi.service.ISpcySmsLogService;
import com.yuncheng.spcyApi.utils.CronUtils;
import com.yuncheng.spcyApi.utils.GetUuIdUtils;
import com.yuncheng.spcyApi.utils.SmsUtils;
import com.yuncheng.spcyApi.utils.StringPatternUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import utils.DateConversionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Component(value = "scheduleJobService")
public class ScheduleJobService {
    private static final Logger log = LoggerFactory.getLogger(ScheduleJobService.class);

    @Resource
    @Lazy
    private CronTaskRegistrar cronTaskRegistrar;

    @Resource
    @Lazy
    private ISpcyScheduleSettingService spcyScheduleSettingService;

    /*@Resource
    @Lazy
    private ISpcyScheduleMbService spcyScheduleMbService;*/

    @Resource
    @Lazy
    private ActiveScheduleTask activeScheduleTask;

    @Resource
    private ISpcySmsLogService spcySmsLogService;

    @Resource
    private SmsUtils smsUtils;

    /**
     * 添加定时任务
     * @param sysJob
     */
    public void addJob(SpcyScheduleSetting sysJob){
        SchedulingRunnable task = new SchedulingRunnable(sysJob.getBeanName(), sysJob.getMethodName(), sysJob.getMethodParams());
        cronTaskRegistrar.addCronTask(task, sysJob.getCronExpression());
    }

    /**
     * 暂停定时任务
     * @param sysJob
     */
    public void pauseJob(SpcyScheduleSetting sysJob){
        SchedulingRunnable task = new SchedulingRunnable(sysJob.getBeanName(), sysJob.getMethodName(), sysJob.getMethodParams());
        cronTaskRegistrar.removeCronTask(task);
    }

    /**
     * 执行一次定时任务
     */
    public void executeOneJob(SpcyScheduleSetting sysJob){
        SchedulingRunnable task = new SchedulingRunnable(cronTaskRegistrar,spcyScheduleSettingService,sysJob.getId(),sysJob.getBeanName(), sysJob.getMethodName(), sysJob.getMethodParams());
        cronTaskRegistrar.addCronTask(task, sysJob.getCronExpression());
    }

    /**
     * 根据定时任务参数-停止定时任务并删除
     */
    public void pauseJobAndDeleteByParam(String param){
        if (StringUtils.isBlank(param)){
            log.error("根据定时任务参数-停止定时任务失败：参数为空！");
            return;
        }
        List<SpcyScheduleSetting> list = spcyScheduleSettingService.list(new LambdaQueryWrapper<SpcyScheduleSetting>()
                .eq(SpcyScheduleSetting::getMethodParams, param));
        if (CollectionUtil.isEmpty(list)){
            return;
        }
        for (SpcyScheduleSetting setting : list){
            this.pauseJob(setting);
            spcyScheduleSettingService.removeById(setting.getId());
        }
    }

    /**
     * 初始化-定时发送短信
     */
    @Async(value = "asyncNormalTask")
    public void initScheduleSms(SpcySmsLog spcySmsLog){
        // 定时任务是否存在
        if (spcySmsLog.getFdsrwsj() == null){
            this.sendSmsWithSchedule(spcySmsLog); // 发送短信

        }else if (spcySmsLog.getFdsrwsj() != null){

            spcySmsLogService.insertSmsLog(spcySmsLog);

            String cron = "";
            try {
                log.info("开始时间：{},结束时间：{}",DateUtil.now(),DateConversionUtils.DateToDays(spcySmsLog.getFdsrwsj()));
                long minute = DateConversionUtils.dateDiffWithDays(DateUtil.now(), DateConversionUtils.DateToDays(spcySmsLog.getFdsrwsj()));
                log.info("日期间隔多少分钟：{}",minute);
                if (minute>59 || minute < 0){
                    cron = CronUtils.getCron(spcySmsLog.getFdsrwsj(),CronUtils.DATEFORMAT_YEAR_FORMAT);
                }else {
                    cron = CronUtils.getCronBetweenWithStrByMiu(String.valueOf(minute));
                }
                log.info("cron表达式：{}",cron);
            } catch (Exception e) {
                log.error("初始化-定时发送短信-获取日期间隔分钟失败：{}",e.getMessage());
            }
            SpcyScheduleSetting sysJob = new SpcyScheduleSetting();
            sysJob.setId(GetUuIdUtils.ReplaceUuId());

            StringBuffer str = new StringBuffer("定时任务-发送短信：");
            str.append("\n").append("[接收对象]").append("为").append("【").append(spcySmsLog.getFjsdx()).append("】");
            str.append("\n").append("[自定义对象]").append("为").append("【").append(spcySmsLog.getFzdydx()).append("】");
            str.append("\n").append("[短信内容]").append("为").append("【").append(spcySmsLog.getFdxnr()).append("】");
            str.append("\n").append("[发送人]").append("为").append("【").append(spcySmsLog.getFusername()).append("】");

            sysJob.setRwName(str.toString());

            sysJob.setCronExpression(cron);
            sysJob.setJobStatus(0);
            sysJob.setBeanName(ScheduleConstant.Bean_Spcy_Schedule_Task);
            sysJob.setMethodName(ScheduleConstant.Schedule_Task_SMS);
            sysJob.setMethodParams(spcySmsLog.getId());
            spcyScheduleSettingService.save(sysJob);

            this.executeOneJob(sysJob);
        }
    }

    /**
     * 发送短信功能
     * @param spcySmsLog
     */
    @Async(value = "asyncNormalTask")
    public void sendSmsWithSchedule(SpcySmsLog spcySmsLog){
        String phones = ""; // 发送对象号码，多个逗号分割

        String dhRegex = ",|，"; // 不区分 中英文逗号，正则表达式

        // 接收对象 xx(phone),xx(phone),
        String fjsdx = spcySmsLog.getFjsdx();
        if (StringUtils.isNotBlank(fjsdx)){
            List<String> regexList = Arrays.asList(fjsdx.split(dhRegex));
            for (String r : regexList){

                // 获取两个括号之间的字符串
                String betweenPhone1 = StringPatternUtils.getStringBetweenTwoChars(r, '(', ')');
                if (StringUtils.isBlank(betweenPhone1)){
                    String betweenPhone2 = StringPatternUtils.getStringBetweenTwoChars(r, '（', '）');
                    if (StringUtils.isNotBlank(betweenPhone2)){
                        if (StringUtils.isBlank(phones)) {
                            phones += betweenPhone2;
                        }else {
                            phones += ","+betweenPhone2;
                        }
                    }
                }else {
                    if (StringUtils.isBlank(phones)) {
                        phones += betweenPhone1;
                    }else {
                        phones += ","+betweenPhone1;
                    }
                }
            }
        }

        log.info("发送短信号码串：{}",phones);

        // 自定义对象 phone-phone-phone
        String fzdydx = spcySmsLog.getFzdydx();
        if (StringUtils.isNotBlank(fzdydx)) {
            List<String> zdydx = Arrays.asList(fzdydx.split("-"));
            for (String p : zdydx) {
                if (StringUtils.isBlank(phones)) {
                    phones += p;
                } else {
                    phones += "," + p;
                }
            }
        }

        log.info("发送短信号码串：{}",phones);
        try {
            if (StringUtils.isNotBlank(fjsdx)) {
                    List<String> phoneList = StringPatternUtils.getListByIds(phones);
                    if (CollectionUtils.isNotEmpty(phoneList)) {
                        for (String p : phoneList) {
                            smsUtils.sendSms(p, spcySmsLog.getFdxnr()); // 发送短信
                        }
                    }
            }else {
                List<String> phoneList = StringPatternUtils.getListByIds(phones);
                if (CollectionUtils.isNotEmpty(phoneList)) {
                    for (String p : phoneList) {
                        smsUtils.sendSmsCase(p, spcySmsLog.getFdxnr()); // 发送短信
                    }
                }
            }

        } catch (NoSuchAlgorithmException e) {
            log.error("发送短信失败【NoSuchAlgorithmException】：{}",e.getMessage());
        } catch (IOException e) {
            log.error("发送短信失败【IOException】：{}",e.getMessage());
        } catch (InvalidKeySpecException e) {
            log.error("发送短信失败【InvalidKeySpecException】：{}",e.getMessage());
        }

        spcySmsLog.setFfssj(new Date());
        spcySmsLog.setFfszt(SpcyConstant.SMS_FSZT_YFS); // 已发送
        spcySmsLogService.insertSmsLog(spcySmsLog);

    }

    /**
     * 初始化 - 推送行政审批数据接口功能
     * @param sqsxid
     * @param type 1: 行政审批数据-推送任务受理信息; 2: 行政审批数据-推送审查结论信息;
     *             3: 行政审批数据-推送材料附件信息; 4: 审批数据 - 推送审评流转办理意见接口
     */
    @Async(value = "asyncNormalTask")
    public void pushXzspDataByJkType(String sqsxid, String type){
        // 两分钟后 cron表达式

        String miu = "1"; // 默认：一分钟后执行

        String rwName = ""; // 任务名称
        String methodName = ""; // 方法名称
        if (type.equals(ScheduleConstant.Xzsp_Data_Rwsl_Code)){
            rwName = ScheduleConstant.Xzsp_Data_Rwsl_Name;
            methodName = ScheduleConstant.Xzsp_Data_Rwsl_Method;

        }else if (type.equals(ScheduleConstant.Xzsp_Data_Scjl_Code)){
            rwName = ScheduleConstant.Xzsp_Data_Scjl_Name;
            methodName = ScheduleConstant.Xzsp_Data_Scjl_Method;
            miu = "3";

        }else if (type.equals(ScheduleConstant.Xzsp_Data_Fjcl_Code)){
            rwName = ScheduleConstant.Xzsp_Data_Fjcl_Name;
            methodName = ScheduleConstant.Xzsp_Data_Fjcl_Code_Method;

        }else if (type.equals(ScheduleConstant.Xzsp_Data_Lzjl_Code)){
            rwName = ScheduleConstant.Xzsp_Data_Lzjl_Name;
            methodName = ScheduleConstant.Xzsp_Data_Lzjl_Method;
            miu = "2";
        }

        // 定时任务cron
        String cron = CronUtils.getCronBetweenWithStrByMiu(miu);

        SpcyScheduleSetting sysJob = new SpcyScheduleSetting();
        sysJob.setId(GetUuIdUtils.NotReplaceUuId());
        sysJob.setRwName(rwName);

        sysJob.setCronExpression(cron);
        sysJob.setJobStatus(0);
        sysJob.setBeanName(ScheduleConstant.Bean_Spcy_Schedule_Task);
        sysJob.setMethodName(methodName);
        sysJob.setMethodParams(sqsxid);
        spcyScheduleSettingService.save(sysJob);

        this.executeOneJob(sysJob);
    }

    /**
     * 定时任务-删除已经移送的申请事项在本地生成的文件
     * @param sqsxid
     * // 五分钟后执行
     */
    public void deleteSqsxLocalWjjlSchedule(String sqsxid){
        // 两分钟后 cron表达式
//        String miu = "50"; // 默认：一分钟后执行

        try {
            /** 30分钟后执行 */
            Date dateTime = DateUtil.offsetMinute(new Date(), 30);
            String cron = CronUtils.getCron(dateTime,CronUtils.DATEFORMAT_YEAR_FORMAT);

            String rwName = ScheduleConstant.Delete_Sqsx_Local_Wjjl_Name; // 任务名称
            String methodName = ScheduleConstant.Delete_Sqsx_Local_Wjjl_Method; // 方法名称

            // 定时任务cron
//        String cron = CronUtils.getCronBetweenWithStrByMiu(miu);

            SpcyScheduleSetting sysJob = new SpcyScheduleSetting();
            sysJob.setId(GetUuIdUtils.ReplaceUuId());
            sysJob.setRwName(rwName);

            sysJob.setCronExpression(cron);
            sysJob.setJobStatus(0);
            sysJob.setBeanName(ScheduleConstant.Bean_Spcy_Schedule_Task);
            sysJob.setMethodName(methodName);
            sysJob.setMethodParams(sqsxid);
            spcyScheduleSettingService.save(sysJob);

            this.executeOneJob(sysJob);
        }catch (Exception e){
            log.error("定时任务-删除已经移送的申请事项在本地生成的文件错误：{}", e.getMessage());
        }

    }

    /**
     * 定时任务 - 计算申请事项-从受理到移送之间的天数
     * @param sqsxid
     */
    public void computeSqsxAcceptedDays(String sqsxid){

        SpcyScheduleSetting sysJob = new SpcyScheduleSetting();
        sysJob.setId(GetUuIdUtils.ReplaceUuId());

        StringBuffer str = new StringBuffer("定时任务-计算申请事项从受理到移送之间的天数。");

        sysJob.setRwName(str.toString());
        sysJob.setCronExpression(ScheduleConstant.Cron_Computed_Accepts_Days);  // 每天凌晨0点
        sysJob.setJobStatus(1);
        sysJob.setBeanName(ScheduleConstant.Bean_Spcy_Schedule_Task);
        sysJob.setMethodName(ScheduleConstant.Xzsp_Data_Computed_Slts_Code_Method);
        sysJob.setMethodParams(null);
        spcyScheduleSettingService.save(sysJob);

        this.addJob(sysJob);  // 添加定时认识
    }

    /**
     * 定时任务-党务会议计划
     */
    @Async(value = "asyncNormalTask")
    public void initScheduleDwhyjh(PartyRsDwhyjh dwhyjh){
        if (dwhyjh == null){
            log.error("定时任务-党务会议计划失败：党务会议计划为空。");
            return;
        }
        if (StringUtils.isBlank(dwhyjh.getId())){
            log.error("定时任务-党务会议计划失败：党务会议计划id为空。");
            return;
        }

        if (StringUtils.isBlank(dwhyjh.getFsfxhzx())){
            log.error("定时任务-党务会议计划失败：党务会议计划id为{}； 执行状态为空",dwhyjh.getId());
            return;
        }

        if (StringUtils.isBlank(dwhyjh.getFyxzt())){
            log.error("定时任务-党务会议计划失败：党务会议计划id为{}; 有效状态为空",dwhyjh.getId());
            return;
        }

        if (StringUtils.isBlank(dwhyjh.getFschykssj())){
            log.error("定时任务-党务会议计划失败：党务会议计划id为{}; 首次会议时间为空",dwhyjh.getId());
            return;
        }

        if (dwhyjh.getFyxzt().equals(SpcyCommonConstant.HYJH_YXZT_NO)){
            this.pauseJobAndDeleteByParam(dwhyjh.getId());
            return;
        }else {
            spcyScheduleSettingService.remove(new LambdaQueryWrapper<SpcyScheduleSetting>()
                    .eq(SpcyScheduleSetting::getMethodParams, dwhyjh.getId()));
        }

        String cron = "";

        Date dsrwTime = DateConversionUtils.convertStringToDateYmdHm(dwhyjh.getFschykssj());

        SpcyScheduleSetting sysJob = new SpcyScheduleSetting();

        // 不循环执行
        if (dwhyjh.getFsfxhzx().equals(SpcyCommonConstant.HYJH_SFXHZX_NO)){
            try {
                long minute = DateConversionUtils.dateDiffWithDays(DateUtil.now(), DateConversionUtils.DateToDays(dsrwTime));
                if (minute>59 || minute < 0){
                    cron = CronUtils.getCron(dsrwTime,CronUtils.DATEFORMAT_YEAR_FORMAT);
                }else {
                    cron = CronUtils.getCronBetweenWithStrByMiu(String.valueOf(minute));
                }
            } catch (Exception e) {
                log.error("获取日期间隔分钟失败：{}",e.getMessage());
            }
            sysJob.setJobStatus(0);
        }

        // 循环执行
        if (dwhyjh.getFsfxhzx().equals(SpcyCommonConstant.HYJH_SFXHZX_YES)){
//            int hour = DateUtil.hour(dsrwTime, true);
//            int minute = DateUtil.minute(dsrwTime);
            cron = CronUtils.getCronEveryFewDaysStr(String.valueOf(dwhyjh.getFhyjgts()));
            sysJob.setJobStatus(1);
        }


        sysJob.setId(GetUuIdUtils.ReplaceUuId());

        StringBuffer titleName = new StringBuffer("定时任务-党务会议计划：");
        titleName.append("\n").append("[会议标题]").append("为").append("【").append(dwhyjh.getFhybt()).append("】");
        titleName.append("\n").append("[首次会议开始时间]").append("为").append("【").append(dwhyjh.getFschykssj()).append("】");
        titleName.append("\n").append("[会议间隔天数]").append("为").append("【").append(dwhyjh.getFhyjgts()).append("】");

        sysJob.setRwName(titleName.toString());

        sysJob.setCronExpression(cron);

        sysJob.setBeanName(ScheduleConstant.Bean_Spcy_Schedule_Task);
        sysJob.setMethodName(ScheduleConstant.Schedule_Task_Dwhyjh);
        sysJob.setMethodParams(dwhyjh.getId());
        spcyScheduleSettingService.save(sysJob);

        // 不循环执行
        if (dwhyjh.getFsfxhzx().equals(SpcyCommonConstant.HYJH_SFXHZX_NO)){
            this.executeOneJob(sysJob);
        }

        // 循环执行
        if (dwhyjh.getFsfxhzx().equals(SpcyCommonConstant.HYJH_SFXHZX_YES)){
            this.addJob(sysJob);
            activeScheduleTask.syncHyjl(dwhyjh, dwhyjh.getId());
        }
    }

    /**
     * 定时任务-申请事项自动选派人员
     * @param ywxx 定时任务自动选派人员信息
     */
    public void initScheduleBySqsxAutoXpry(SpcySqsxYwxx ywxx){

        List<SpcyScheduleSetting> list = spcyScheduleSettingService.list(new LambdaQueryWrapper<SpcyScheduleSetting>()
                .eq(SpcyScheduleSetting::getMethodParams, ywxx.getId()));
        if (CollectionUtil.isNotEmpty(list)){
            return;
        }

        try {
            // 两分钟后 cron表达式
            int miu = 40; // 默认：30分钟后执行

            String rwName = "定时任务-申请事项自动选派人员"; // 任务名称
            String methodName = ScheduleConstant.Schedule_Task_Sqsx_Auto_Xpry; // 方法名称

            // 定时任务cron
            String cron = CronUtils.getCronBetweenWithStrByMiu(0, miu);
//        String cron = CronUtils.getCronBetweenWithStrByHour(0, 1);

            SpcyScheduleSetting sysJob = new SpcyScheduleSetting();
            sysJob.setId(GetUuIdUtils.ReplaceUuId());
            sysJob.setRwName(rwName);

            sysJob.setCronExpression(cron);
            sysJob.setJobStatus(1);
            sysJob.setBeanName(ScheduleConstant.Bean_Spcy_Schedule_Task);
            sysJob.setMethodName(methodName);
            sysJob.setMethodParams(ywxx.getId());
            spcyScheduleSettingService.save(sysJob);

            this.addJob(sysJob);
        }catch (Exception e){
            log.error("定时任务-申请事项自动选派人员-定时任务错误：{}", e.getMessage());
        }

    }

    /**
     * 定时任务-发送选派人员短信过期确认
     * @param methodParams 选派记录id
     */
    public void initScheduleBySendXprySms(String methodParams){
        if (StringUtils.isBlank(methodParams)){
            return;
        }

        List<SpcyScheduleSetting> list = spcyScheduleSettingService.list(new LambdaQueryWrapper<SpcyScheduleSetting>()
                .eq(SpcyScheduleSetting::getMethodParams, methodParams));
        if (CollectionUtil.isNotEmpty(list)){
            return;
        }

        try {
            // 两分钟后 cron表达式
//        int miu = 30; // 默认：30分钟后执行

            String rwName = "定时任务-发送选派人员短信过期确认"; // 任务名称
            String methodName = ScheduleConstant.Schedule_Task_Expire_Xpry_Qr_Sms; // 方法名称

            // 定时任务cron
//        String cron = CronUtils.getCronBetweenWithStrByMiu(0, miu);
            // 默认：30分钟后执行
            Date dateTime = DateUtil.offsetMinute(new Date(), ScheduleConstant.Schedule_Task_Expire_Xpry_Qr_Sms_Cron_Miu);
            String cron = CronUtils.getCron(dateTime,CronUtils.DATEFORMAT_YEAR_FORMAT);

            SpcyScheduleSetting sysJob = new SpcyScheduleSetting();
            sysJob.setId(GetUuIdUtils.ReplaceUuId());
            sysJob.setRwName(rwName);

            sysJob.setCronExpression(cron);
            sysJob.setJobStatus(0);
            sysJob.setBeanName(ScheduleConstant.Bean_Spcy_Schedule_Task);
            sysJob.setMethodName(methodName);
            sysJob.setMethodParams(methodParams);
            spcyScheduleSettingService.save(sysJob);

            this.executeOneJob(sysJob);

        }catch (Exception e){
            log.error("定时任务-发送选派人员短信过期确认-错误：{}", e.getMessage());
        }

    }

    /**
     * 定时任务-移除-根据方法参数
     * @param methodParams 方法参数
     */
    public void removeScheduleByMethodParams(String methodParams){
        if (StringUtils.isBlank(methodParams)){
            return;
        }

        try {
            List<SpcyScheduleSetting> list = spcyScheduleSettingService.list(new LambdaQueryWrapper<SpcyScheduleSetting>()
                    .eq(SpcyScheduleSetting::getMethodParams, methodParams));
            if (CollectionUtil.isNotEmpty(list)){
                if (list.get(0).getJobStatus() == 0){
                    return;
                }

                SpcyScheduleSetting setting = list.get(0);
                setting.setJobStatus(0);
                spcyScheduleSettingService.updateById(setting);

                pauseJob(setting);
            }

        }catch (Exception e){
            log.error("定时任务-移除-根据方法参数-错误：{}", e.getMessage());
        }

    }
}
